from datetime import timedelta
from pathlib import Path
import uvicorn

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from fastapi.responses import HTMLResponse
from fastapi.openapi.docs import (
    get_redoc_html,
    get_swagger_ui_html,
    get_swagger_ui_oauth2_redirect_html,
)

from routers.files import files_router
from routers.statistics import statistics_router
from routers.forecast import forecast_router
from routers.schedule import schedule_router
from routers.doctors import doctors_router
from routers.tasks import tasks_router
from routers.users import user_router
from routers.roles import roles_router
from routers.modality import modality_router
from db.config import SWAGGER_STATIC
from db.db import AsyncSession, get_session
from db.users import authenticate_user, create_access_token


ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24


app = FastAPI(
    docs_url=None,
    redoc_url=None,
)

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/v1/token")

app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        "*",
        "http://frontend:6781",
        "http://localhost:3000",
        "http://0.0.0.0:6781",
        "http://213.171.28.251:6781",
    ],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.include_router(files_router, prefix="/api/v1/files", tags=["files"])
app.include_router(statistics_router, prefix="/api/v1/statistics", tags=["statistics"])
app.include_router(forecast_router, prefix="/api/v1/forecast", tags=["forecast"])
app.include_router(schedule_router, prefix="/api/v1/schedule", tags=["schedule"])
app.include_router(doctors_router, prefix="/api/v1/doctors", tags=["doctors"])
app.include_router(tasks_router, prefix="/api/v1/tasks", tags=["tasks"])
app.include_router(user_router, prefix="/api/v1/users", tags=["users"])
app.include_router(roles_router, prefix="/api/v1/roles", tags=["roles"])
app.include_router(modality_router, prefix="/api/v1/modality", tags=["modality"])

app.mount("/static", StaticFiles(directory=SWAGGER_STATIC), name="static")


@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html() -> HTMLResponse:
    """
    Endpoint to support static swagger.

    Returns:
        HTTP response.
    """
    return get_swagger_ui_html(
        openapi_url="/openapi.json",
        title="Swagger UI",
        oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
        swagger_js_url="/static/swagger-ui-bundle.js",
        swagger_css_url="/static/swagger-ui.css",
    )


@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect() -> HTMLResponse:
    """
    Swagger UI redirect.

    Returns:
        HTTP response.
    """
    return get_swagger_ui_oauth2_redirect_html()


@app.get("/redoc", include_in_schema=False)
async def redoc_html() -> HTMLResponse:
    """
    Endpoint to support static ReDoc.

    Returns:
        HTTP response.
    """
    return get_redoc_html(
        openapi_url="/openapi.json",
        title="AUTH",
        redoc_js_url="/static/redoc.standalone.js",
    )


@app.post("/token", tags=["auth"])
async def login_for_access_token(
    form_data: OAuth2PasswordRequestForm = Depends(),
    session: AsyncSession = Depends(get_session),
):
    """Авторизация пользователя."""
    user = await authenticate_user(
        username=form_data.username, password=form_data.password, session=session
    )
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.username},
        expires_delta=access_token_expires,
    )
    return {
        "access_token": access_token,
        "token_type": "bearer",
        "role": user.role.name,
        "fullname": user.username,
    }


@app.on_event('startup')
async def startup_event():
    app.mount('/download', StaticFiles(directory="download"), name="download")

if __name__ == "__main__":
    Path("download").mkdir(exist_ok=True)
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
